<template>
  <div
    v-loading="loading"
    element-loading-text="数据加载中..."
    element-loading-spinner="el-icon-loading"
    :style="{ height: tableHeight2 }"
    :class="['l-table', isPage ? 'l-table--haspagination' : '']"
  >
    <el-table
      :data="tableShowData"
      style="width: 100%"
      :height="tableHeight"
      :max-height="maxHeight"
      size="mini"
      :cell-style="cellStyle || { padding: '2px 0' }"
      :header-cell-style="{ padding: '2px 0' }"
      :stripe="stripe"
      :border="border"
      :fit="fit"
      :show-header="showHeader"
      :highlight-current-row="highlightCurrentRow"
      :current-row-key="currentRowKey"
      :row-key="rowKey"
      :row-class-name="rowClassName"
      :cell-class-name="cellClassName"
      :header-row-class-name="headerRowClassName"
      :header-cell-class-name="headerCellClassName"
      :default-expand-all="defaultExpandAll"
      :expand-row-keys="expandRowKeys"
      :default-sort="defaultSort"
      :tooltip-effect="tooltipEffect"
      :show-summary="showSummary"
      :sum-text="sumText"
      :summary-method="getSummaries"
      :span-method="spanMethod"
      :select-on-indeterminate="selectOnIndeterminate"
      :indent="indent"
      :lazy="lazy"
      :load="load"
      :tree-props="treeProps"
      :row-style="rowStyle"
      @select="handleSelect"
      @select-all="handleSelectAll"
      @selection-change="selectionChange"
      @cell-mouse-enter="cellMouseEnter"
      @cell-mouse-leave="cellMouseLeave"
      @cell-click="cellClick"
      @cell-dblclick="cellDblclick"
      @row-click="rowClick"
      @row-contextmenu="rowContextmenu"
      @row-dblclick="rowDblclick"
      @header-click="headerClick"
      @header-contextmenu="headerContextmenu"
      @sort-change="sortChange"
      @filter-change="filterChange"
      @current-change="currentChange"
      @header-dragend="headerDagend"
      @expand-change="expandChange"
      ref="learunTable"
    >
      <!-- 拖动排序  -->
      <el-table-column align="center" width="45" v-if="isSortable && !isTree">
        <template slot="header">
          <i class="el-icon-sort" />
        </template>
        <template>
          <span class="learun-table__drag-handler">
            <i class="el-icon-rank" />
          </span>
        </template>
      </el-table-column>

      <el-table-column
        v-if="isExpand"
        :fixed="isFixed"
        type="expand"
        v-slot="scope"
        width="28"
      >
        <slot v-bind="scope" name="table_expand"></slot>
      </el-table-column>

      <el-table-column
        v-if="isShowNum"
        :label="ShowNumLabel"
        :fixed="isFixed"
        type="index"
        :index="indexMethod"
      >
      </el-table-column>

      <el-table-column
        v-if="isMultiSelect"
        :fixed="isFixed"
        type="selection"
        width="45"
        header-align="center"
      ></el-table-column>

      <template v-for="(item, index) in myColumns">
        <el-table-column
          :key="item.prop || index"
          v-bind="item"
          :show-overflow-tooltip="item.isNotAutoWrap == true ? true : false"
          :fixed="isSortable && !isTree ? false : item.fixed"
          :sortable="sortable || item.sortable"
        >
          <template v-slot:header="{ column }">
            <span v-if="isRequired(column.property)" style="color: red">*</span
            ><span>{{ column.label }}</span>
          </template>
          <template v-slot="slotProps">
            <slot v-bind="slotProps" :name="item.prop">{{
              columnText(slotProps.$index, slotProps.row, item, slotProps)
            }}</slot>
          </template>
        </el-table-column>
      </template>
      <slot></slot>
    </el-table>
    <div v-if="isPage" class="l-table--pagination">
      <el-pagination
        small
        background
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        :current-page.sync="currentPage"
        :page-sizes="pageSizes || [20, 50, 100, 200]"
        :page-size.sync="pageSize2"
        layout="total, sizes, prev, pager, next, jumper"
        :total="pageTotal"
      >
      </el-pagination>
    </div>
    <l-drawer
      :title="$t('表格列设置')"
      :visible.sync="columnsVisible"
      :showOk="false"
      :showClose="false"
      :wrapperClosable="true"
      size="320px"
    >
      <el-tree
        node-key="prop"
        :default-checked-keys="defaultCheckedKeys"
        show-checkbox
        :data="columns"
        @check="handleColumnsCheck"
      >
      </el-tree>
    </l-drawer>
  </div>
</template>
<script>
import tableEvent from "@util/tableEvent";
//import dynamicColumn from "./dynamic-column";
export default {
  name: "l-table",
  mixins: [tableEvent()],
  components: {
    //dynamicColumn
  },
  props: {
    columns: {
      type: Array,
      default: () => [],
    },
    dataSource: {
      type: Array,
      default: () => [],
    },
    loading: {
      type: Boolean,
      default: false,
    },
    height: {
      type: [String, Number],
      default: "100%",
    },
    maxHeight: {
      type: [String, Number],
    },
    stripe: {
      type: Boolean,
      default: false,
    },
    border: {
      type: Boolean,
      default: true,
    },
    fit: {
      type: Boolean,
      default: true,
    },
    showHeader: {
      type: Boolean,
      default: true,
    },
    highlightCurrentRow: {
      type: Boolean,
      default: false,
    },

    currentRowKey: [String, Number],
    rowKey: [String, Function],

    rowClassName: [String, Function],
    cellClassName: [String, Function],
    headerRowClassName: [String, Function],
    headerCellClassName: [String, Function],

    defaultExpandAll: Boolean,
    expandRowKeys: {
      type: Array,
    },

    defaultSort: Object,

    tooltipEffect: String,

    showSummary: {
      type: Boolean,
      default: false,
    },
    sumText: {
      type: String,
      default: "合计",
    },
    summaryMethod: Function,

    spanMethod: Function,

    selectOnIndeterminate: {
      type: Boolean,
      default: true,
    },

    indent: {
      type: Number,
      default: 16,
    },
    lazy: Boolean,
    load: Function,
    treeProps: Object,

    isPage: {
      type: Boolean,
      default: false,
    },
    pageSizes: Array,
    pageTotal: {
      type: Number,
      default: 0,
    },
    tablePage: {
      type: Number,
      default: 1,
    },

    isShowNum: {
      type: Boolean,
      default: true,
    },
    ShowNumLabel: {
      type: String,
      default: "序号",
    },
    isMultiSelect: Boolean,
    reserveSelection: {
      type: Boolean,
      default: true,
    },

    isTree: {
      type: Boolean,
      default: false,
    },
    pidKey: {
      type: String,
    },
    selectKey: String,
    sortable: {
      type: Boolean,
      default: false,
    },
    isSortable: {
      type: Boolean,
      default: false,
    },

    isExpand: {
      type: Boolean,
      default: false,
    },
    isChild: {
      type: Boolean,
      default: false,
    },
    rowStyle: [Function, Object],
    cellStyle: [Function, Object],
    pageSize: {
      type: Number,
      default: 50,
    },
    required: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      selectedData: [],
      columnsVisible: false,
      columnsChecks: null,
      pageSize3: 0,
    };
  },
  mounted() {
    this.setSort();
    if (this.isChild) {
      const list = this.$el.querySelectorAll(".el-table__row");
      list.forEach((row) => {
        row.classList.add("el-table__row2");
        row.classList.remove("el-table__row");
      });
    }
  },
  computed: {
    pageSize2: {
      get() {
        if (this.pageSize3 != 0) {
          return this.pageSize3;
        }
        return this.pageSize;
      },
      set(val) {
        this.pageSize3 = val;
        this.$emit("update:pageSize", val);
      },
    },
    isFixed() {
      return (
        this.columns.find((item) => {
          return item.fixed == true;
        }) != undefined && !this.isSortable
      );
    },
    tableHeight() {
      if (this.height == "notset" || this.isChild) {
        return;
      } else {
        return "100%";
      }
    },
    tableHeight2() {
      if (this.height == "notset" || this.isChild) {
        return;
      } else {
        return this.height;
      }
    },
    currentPage: {
      get() {
        if (!this.$validatenull(this.tablePage)) {
          return this.tablePage;
        } else {
          return 1;
        }
      },
      set(val) {
        this.$emit("update:tablePage", val);
      },
    },
    tableShowData() {
      if (this.isTree) {
        return this.$toTree(
          this.dataSource,
          this.multiSelectKey,
          this.pidKey,
          this.multiSelectKey,
          this.multiSelectKey
        );
      } else {
        return this.dataSource;
      }
    },
    multiSelectKey() {
      if (this.selectKey) {
        return this.selectKey;
      } else if (typeof this.rowKey == "string") {
        return this.rowKey;
      } else {
        return this.selectKey;
      }
    },
    selectedValues() {
      return this.selectedData.map((t) => t[this.multiSelectKey]);
    },
    defaultCheckedKeys() {
      return this.columns
        .filter((t) => t.isNotShow != true)
        .map((t) => t.prop)
        .filter((item) => {
          if (this.columnsChecks) {
            return this.columnsChecks.findIndex((t) => t === item) > -1;
          } else {
            return true;
          }
        });
    },
    myColumns() {
      if (this.columns.length == 0) {
        return [{ label: "", prop: "learun_null", minWidth: "1" }];
      }
      let res;
      if (this.columnsChecks != null) {
        res = this.columns.filter(
          (t) => this.columnsChecks.indexOf(t.prop) != -1
        );
      } else {
        res = this.columns.filter(
          (t) => this.defaultCheckedKeys.indexOf(t.prop) != -1
        );
      }

      if (res.length == 0) {
        return [{ label: "", prop: "learun_null", minWidth: "1" }];
      }
      return res;
    },
  },
  watch: {
    dataSource() {
      if (this.isChild) {
        const list = this.$el.querySelectorAll(".el-table__row");
        list.forEach((row) => {
          row.classList.add("el-table__row2");
          row.classList.remove("el-table__row");
        });
      }
      this.selectRows();
    },
  },
  methods: {
    indexMethod(index) {
      if (this.isPage) {
        return (this.currentPage - 1) * this.pageSize2 + index + 1;
      } else {
        return index + 1;
      }
    },
    handleSizeChange(val) {
      this.pageSize2 = val;
      this.$emit("loadPageData", { rows: val, page: this.currentPage });
      //console.log(`每页 ${val} 条`);
    },
    handleCurrentChange(val) {
      this.currentPage = val;
      this.$emit("loadPageData", { rows: this.pageSize2, page: val });
    },
    doLayout() {
      this.$nextTick(() => {
        this.$refs.learunTable.doLayout();
      });
    },

    // 关于多选
    reset() {
      this.selectedData = [];
      this.$refs.learunTable.clearSelection();
    },
    getSelected() {
      return this.$deepClone(this.selectedData);
    },
    handleSelect(selection, row) {
      if (!this.reserveSelection) {
        this.$emit("select", selection, row);
        return;
      }
      // 获取增加项
      const addList = selection.filter(
        (t) => this.selectedValues.indexOf(t[this.multiSelectKey]) == -1
      );
      if (addList.length > 0) {
        this.selectedData = addList.concat(this.selectedData);
      } else {
        // 获取当前页面没有被选中的
        let notSelectedList = this.dataSource.filter(
          (t) =>
            selection.findIndex(
              (t2) => t2[this.multiSelectKey] == t[this.multiSelectKey]
            ) == -1
        );
        // 获取减少项
        let deleteList = notSelectedList.filter(
          (t) => this.selectedValues.indexOf(t[this.multiSelectKey]) != -1
        );
        this.selectedData = this.selectedData.filter(
          (t) =>
            deleteList.findIndex(
              (t2) => t2[this.multiSelectKey] == t[this.multiSelectKey]
            ) == -1
        );
      }

      this.$emit("select", selection, row);
    },
    handleSelectAll(selection) {
      if (this.isTree) {
        if (this.dataSource.length > 0) {
          if (
            this.dataSource.filter(
              (t) => this.selectedValues.indexOf(t[this.multiSelectKey]) != -1
            ).length < this.dataSource.length
          ) {
            let needSelectData = this.dataSource.map(
              (t) => t[this.multiSelectKey]
            );
            this.selectTreeRows2(this.tableShowData, needSelectData);
            this.handleSelect(this.dataSource);
          } else {
            // 表示全部不选中
            this.$refs.selectTable.clearSelection();
            this.handleSelect([]);
          }
        }
      } else {
        this.handleSelect(selection);
      }
      this.$emit("selectAll", selection);
    },
    selectRows() {
      if (!this.isMultiSelect || !this.reserveSelection) {
        return;
      }
      this.$nextTick(() => {
        if (this.isTree) {
          this.selectTreeRows(this.tableShowData);
        } else {
          this.dataSource.forEach((row) => {
            if (this.selectedValues.indexOf(row[this.multiSelectKey]) != -1) {
              this.$refs.learunTable.toggleRowSelection(row, true);
            }
          });
        }
      });
    },
    selectTreeRows(data) {
      data.forEach((row) => {
        if (this.selectedValues.indexOf(row.value) != -1) {
          this.$refs.selectTable.toggleRowSelection(row, true);
        }
        if (row.children) {
          this.selectTreeRows(row.children);
        }
      });
    },
    selectTreeRows2(data, selectValues) {
      data.forEach((row) => {
        if (selectValues.indexOf(row.value) != -1) {
          this.$refs.selectTable.toggleRowSelection(row, true);
        }
        if (row.children) {
          this.selectTreeRows2(row.children, selectValues);
        }
      });
    },

    // 动态显示列
    openColumnsSetting() {
      this.columnsVisible = true;
    },
    handleColumnsCheck($node, data) {
      this.columnsChecks = data.checkedKeys.concat(data.halfCheckedKeys);
      this.$nextTick(() => {
        this.$refs.learunTable.doLayout();
      });
      this.$emit("handleColumnsCheck");
    },
    getColumnsCheck() {
      return this.columnsChecks;
    },
    setColumnsCheck(columnsChecks) {
      this.columnsChecks = columnsChecks;
    },

    // 行排序(暂时不支持树形结构)
    setSort() {
      const callback = () => {
        const el = this.$refs.learunTable.$el.querySelectorAll(
          ".el-table__body-wrapper > table > tbody"
        )[0];

        this.dragSortable = window.Sortable.create(el, {
          ghostClass: "learun-table__sortable",
          handle: ".learun-table__drag-handler",
          onEnd: (evt) => {
            const oldindex = evt.oldIndex;
            const newindex = evt.newIndex;
            const targetRow = this.dataSource.splice(oldindex, 1)[0];
            this.dataSource.splice(newindex, 0, targetRow);
            this.$emit(
              "sortable-change",
              oldindex,
              newindex,
              targetRow,
              this.dataSource
            );
          },
        });
      };
      if (this.isSortable && !this.isTree) {
        this.$nextTick(() => {
          callback();
        });
      }
    },

    columnText(index, row, column, scope) {
      if (typeof column.formatter == "function") {
        return column.formatter({
          row: row,
          column: scope.column,
          cellValue: row[column.prop],
          index: index,
        });
      } else {
        this.loadCellData(row[column.prop], column);
        return this.getCellText(row[column.prop], column);
      }
    },
    loadCellData(value, { dataType, dataCode }) {
      if (dataType && value) {
        switch (dataType) {
          case "dataItem":
            this.lr_loadDataItem && this.lr_loadDataItem(dataCode);
            break;
          case "dataSource":
            this.lr_loadDataSourceData && this.lr_loadDataSourceData(dataCode);
            break;
          case "company":
            this.lr_loadCompanys && this.lr_loadCompanys();
            break;
          case "department":
            this.lr_loadDepartment && this.lr_loadDepartment(value);
            break;
          case "role":
            this.lr_loadRole && this.lr_loadRole(value);
            break;
          case "post":
            this.lr_loadPost && this.lr_loadPost(value);
            break;
          case "user":
            this.lr_loadUsers && this.lr_loadUsers(value);
            break;
          case "areas":
            if (this.lr_loadAreas) {
              const areaList = value.split(",");
              if (areaList.length == 3) {
                this.lr_loadAreas(0),
                  this.lr_loadAreas(areaList[0]),
                  this.lr_loadAreas(areaList[1]);
              }
            }
            break;
        }
      }
    },
    getCellText(
      value,
      { dataType, dataCode, options, valueKey, labelKey, format }
    ) {
      if (window.$validatenull(value)) {
        return "";
      }
      if (!this.lr_dataSourceName) {
        return value;
      }
      switch (dataType) {
        case "mydata": {
          const dataSource = [];
          this.findTreeItem(options, dataSource); //静态数据
          return this.lr_dataSourceName(dataSource, value, "value", "label");
        }
        case "dataItem":
          return this.lr_dataItemName(this.lr_dataItem[dataCode], value);
        case "dataSource":
          return this.lr_dataSourceName2(dataCode, value, valueKey, labelKey);
        case "datetime":
          return window.$formatDate(value, format || "yyyy-MM-dd hh:mm:ss");
        case "company":
          return this.lr_loadCompanyName(value);
        case "department":
          return this.lr_departmentNameByOne(value);
        case "role":
          return (this.lr_role[value] || {})[labelKey || "f_FullName"] || "";
        case "post":
          return (this.lr_post[value] || {})[labelKey || "f_FullName"] || "";
        case "user":
          return this.lr_userName(value);
        case "areas":
          return this.lr_areasName(value);
        default:
          return value;
      }
    },
    findTreeItem(arr, res) {
      arr.forEach((t) => {
        res.push({ value: t.value, label: t.label });
        if (t.children) {
          this.findTreeItem(t.children, res);
        }
      });
    },

    getSummaries(param) {
      this.$nextTick(() => {
        this.$refs.learunTable.doLayout();
      });

      if (this.summaryMethod) {
        return this.summaryMethod(param);
      }

      const { columns, data } = param;
      const sums = [];
      columns.forEach((column, index) => {
        if (index === 0) {
          sums[index] = this.sumText;
          return;
        }

        const myColumn = this.myColumns.find((t) => t.prop == column.property);

        if (myColumn && myColumn.isSummary) {
          const values = data.map((item) => Number(item[column.property]));
          if (!values.every((value) => isNaN(value))) {
            sums[index] = values.reduce((prev, curr) => {
              const value = Number(curr);
              if (!isNaN(value)) {
                return prev + curr;
              } else {
                return prev;
              }
            }, 0);
            //sums[index] += ' 元';
          } else {
            sums[index] = "N/A";
          }
        } else {
          sums[index] = "";
        }
      });

      return sums;
    },
    isRequired(property) {
      let myColumn = this.columns.find((t) => t.prop == property);
      if (!myColumn) {
        return false;
      }
      return myColumn.required;
    },
    validate() {
      let res = true;
      if (this.required) {
        if (this.dataSource.length == 0) {
          this.$message({
            type: "error",
            message: this.$t(`请添加表格数据`),
          });
          return false;
        }
      }
      try {
        this.dataSource.forEach((row, index) => {
          this.columns.forEach((col) => {
            if (!col.isHidden) {
              if (col.required && this.$validatenull(row[col.prop])) {
                this.$message({
                  type: "error",
                  message: this.$t(`请输入第${index + 1}行-${col.label}`),
                });
                res = false;
                throw new Error();
              }

              if (col.patterns && col.patterns.length > 0) {
                col.patterns.forEach((pattern) => {
                  if (
                    pattern.reg &&
                    !this.$validatenull(row[col.prop]) &&
                    !new RegExp(
                      pattern.reg.substring(1, pattern.reg.length - 1)
                    ).test(row[col.prop])
                  ) {
                    this.$message({
                      type: "error",
                      message: this.$t(
                        `${pattern.msg}第${index + 1}行-${col.label}`
                      ),
                    });
                    res = false;
                    throw new Error();
                  }
                });
              }
            }
          });
        });
      } catch (error) {}
      return res;
    },
  },
};
</script>
<style lang="less">
@import "./index.less";
</style>
